#include "dma.h"

/**
 * 简述：初始化 DMA1 通道4 传输数据到 USART1_Tx
 * 参数：无
 * 返回值：无
 **/
void dma1_ch4_to_usart1_tx_init(void)
{
	DMA_InitTypeDef DMA_InitStruct;
	
	// 使能 DMA1 时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	// 初始化 DMA
	DMA_InitStruct.DMA_BufferSize         = 0;  // 暂时不知道将要传输的数据数目
	DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralDST;  // 内存到外设
	DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;  // 禁用内存到内存的传输
	DMA_InitStruct.DMA_MemoryBaseAddr     = 0;  // 暂时不知道内存地址
	DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;  // 内存数据宽度：字节
	DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;  // 内存地址自增
	DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;  // 普通模式
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) &USART1->DR;  // 外设地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  // 外设数据宽度：字节
	DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;  // 外设地址固定
	DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;   // 最高软件优先级
	// void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
	DMA_Init(DMA1_Channel4, &DMA_InitStruct);
	
	// 禁用 DMA1 通道4
	// void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
	DMA_Cmd(DMA1_Channel4, DISABLE);
}

/**
 * 简述：DMA1 通道4 传输数据到 USART1_Tx
 * 参数：buf  数据缓冲区
 *       size 数据数目
 * 返回值：无
 **/
void dma1_ch4_to_usart1_tx(char *buf, int size)
{
	// 关闭 USART1 DMA
	// void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);
	USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
	// 关闭 DMA1 通道4，只有关闭 DMA 才能修改 CNDTR 寄存器
	DMA_Cmd(DMA1_Channel4, DISABLE);
	
	// 设置内存地址
	DMA1_Channel4->CMAR = (uint32_t) buf;
	// 设置传输数目
	DMA1_Channel4->CNDTR = size;
	// void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 
	//DMA_SetCurrDataCounter(DMA1_Channel4, size);
	
	// 打开 USART1 DMA
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
	// 打开 DMA1 通道4
	DMA_Cmd(DMA1_Channel4, ENABLE);
}

/**
 * 简述：DMA1 通道1 从 src 传输数据到 dest
 * 参数：dest 目标数据缓冲区
 *       src  源数据缓冲区
 *       size 数据数目
 * 返回值：无
 **/
void dma1_ch1_m2m(char *dest, char *src, int size)
{
	DMA_InitTypeDef DMA_InitStruct;
	
	// 使能 DMA1 时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	DMA_Cmd(DMA1_Channel1, DISABLE);
	
	// 初始化 DMA，目标内存当作外设
	DMA_InitStruct.DMA_BufferSize         = size;  // 暂时不知道将要传输的数据数目
	DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralDST;  // 内存到外设
	DMA_InitStruct.DMA_M2M                = DMA_M2M_Enable;  // 使能内存到内存的传输
	DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t) src;  // 暂时不知道内存地址
	DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;  // 内存数据宽度：字节
	DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;  // 内存地址自增
	DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;  // 普通模式
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) dest;  // 外设地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  // 外设数据宽度：字节
	DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Enable;  // 外设地址自增
	DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;   // 最高软件优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStruct);
	
	DMA_Cmd(DMA1_Channel1, ENABLE);
}
